#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_CORE_AVAILABLE_PATH/nginx-vhosts/functions"
source "$PLUGIN_AVAILABLE_PATH/letsencrypt/functions"
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/config"


letsencrypt_acmeproxy_on () {
  #shellcheck disable=SC2034
  declare desc="enable ACME proxy for an app"
  local app="$1"; verify_app_name "$app"
  local acme_port="$2"

  local app_root="$DOKKU_ROOT/$app"
  local app_config_dir="$app_root/nginx.conf.d"

  dokku_log_info1 "Enabling ACME proxy for ${app}..."

  # ensure the nginx.conf.d directory exists
  [[ -d "$app_config_dir" ]] || mkdir "$app_config_dir"


  # insert acme_port into config template, place resulting config in nginx.conf.d
  sigil -f "$PLUGIN_AVAILABLE_PATH/letsencrypt/templates/letsencrypt.conf.sigil" \
    ACME_PORT="$acme_port" \
    > "$app_config_dir/letsencrypt.conf"

  restart_nginx
}


letsencrypt_acmeproxy_off() {
  #shellcheck disable=SC2034
  declare desc="disable ACME proxy for an app"
  local app="$1"; verify_app_name "$app"

  local app_root="$DOKKU_ROOT/$app"
  local app_config_dir="$app_root/nginx.conf.d"

  dokku_log_info1 "Disabling ACME proxy for $app..."

  [[ -f "$app_config_dir/letsencrypt.conf" ]] && rm "$app_config_dir/letsencrypt.conf"

  restart_nginx
}

letsencrypt_link () {
  #shellcheck disable=SC2034
  declare desc="symlink let's encrypt certificates so they can be found by dokku"

  local app="$1"; verify_app_name "$app"
  local config_dir="$2"

  local app_root="$DOKKU_ROOT/$app"
  local le_root="$app_root/letsencrypt"

  dokku_log_info1 "Installing let's encrypt certificates"

  # link the current config directory to 'current'
  ln -nsf "$config_dir" "$le_root/certs/current"

  # install the let's encrypt certificate for the app
  if [[ -z $DOKKU_APP_NAME ]]; then
    dokku certs:add "$app" "$le_root/certs/current/fullchain.pem" "$le_root/certs/current/key.pem"
  else
    dokku certs:add "$le_root/certs/current/fullchain.pem" "$le_root/certs/current/key.pem"
  fi
}


letsencrypt_acme () {
  #shellcheck disable=SC2034
  declare desc="perform actual ACME validation procedure"
  local app="$1"
  local acme_port="$2"

  letsencrypt_create_root "$app"

  dokku_log_info1 "Getting letsencrypt certificate for ${app}..."

  # read simp_le arguments from appropriate config file into the config array
  local config_dir="$(letsencrypt_configure_and_get_dir "$app")"
  read -r -a config < "$config_dir/config"

  eval "$(config_export global)"
  eval "$(config_export app "$app")"

  local graceperiod="${DOKKU_LETSENCRYPT_GRACEPERIOD:-$((60 * 60 * 24 * 30))}"

  # run letsencrypt as a docker container using "certonly" mode
  # port 80 of the standalone webserver will be forwarded by the proxy
  set +e
  docker run --rm \
    -p "$acme_port:80" \
    -v "$config_dir:/certs" \
    "${PLUGIN_IMAGE}:${PLUGIN_IMAGE_VERSION}" \
    -f account_key.json \
    -f account_reg.json \
    -f fullchain.pem -f chain.pem -f cert.pem -f key.pem \
    --valid_min "${graceperiod}" \
    "${config[@]}"

  local simple_result=$?
  set -e

  # handle simp_le return codes
  # see https://github.com/kuba/simp_le/blob/master/README.rst#manifest
  if [[ $simple_result == 0 ]]; then
    # got certificate
    dokku_log_info1 "Certificate retrieved successfully."

  elif [[ $simple_result == 1 ]]; then
    # no renewal necessary
    dokku_log_info1 "No renewal necessary"

  else
    # error - don't try to link certificates
    dokku_log_info1 "Certificate retrieval failed!"
    return

  fi

  letsencrypt_link "$app" "$config_dir"
  nginx_build_config "$app"
}


letsencrypt_default_cmd() {
  #shellcheck disable=SC2034
  declare desc="Validate an app's domains and retrieve a certificate"
  local cmd="letsencrypt"

  # Support --app/$DOKKU_APP_NAME flag by reordering args into "$cmd $DOKKU_APP_NAME $@"
  local argv=("$@")
  [[ ${argv[0]} == "$cmd" ]] && shift 1
  [[ ! -z $DOKKU_APP_NAME ]] && set -- $DOKKU_APP_NAME $@
  set -- $cmd $@
  ##

  local app="$2"

  [[ -z "$app" ]] && echo "Please specify an app to run the command on" && exit 1

  dokku_log_info2 "Let's Encrypt $app"

  # dynamically choose a port for the letsencrypt standalone authenticator
  local acme_port=$(get_available_port)

  letsencrypt_check_email "$app"

  letsencrypt_update

  letsencrypt_acmeproxy_on "$app" "$acme_port"
  letsencrypt_acme "$app" "$acme_port" || true    # remove ACME proxy even if this fails
  letsencrypt_acmeproxy_off "$app"

  dokku_log_verbose "done"

}

letsencrypt_default_cmd "$@"
